﻿using Messhall.Framework.Domain.DomainObject;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Messhall.Framework.Repository.UnitOfWork;
using Microsoft.EntityFrameworkCore;
using System.Linq.Expressions;
using Messhall.Framework.Domain.Repository;

namespace Messhall.Framework.Repository.Repositorys
{
    public class RepositoryBase<BoT, TEntity> : RepositoryReadSqlBase, IRepositoryBase<BoT, TEntity>
        where BoT : BoBase
        where TEntity : EntityBase
    {
        protected readonly DbContext _dbContext;

        public RepositoryBase(IDbContextUnitOfWork dbContext) : base(dbContext)
        {
            _dbContext = (DbContext) dbContext;
        }

        private DbSet<TEntity> Set()
        {
            return this.Set<TEntity>();
        }

        public DbSet<T> Set<T>() where T : EntityBase
        {
            return _dbContext.Set<T>();
        }

        #region IRepositoryReadBase

        /// <summary>
        /// 实体操作
        /// </summary>
        public virtual DbSet<TEntity> DbSetEntity => Set();

        /// <summary>
        /// 寻找业务所有对象
        /// </summary>
        public virtual async Task<List<BoT>> FindAllAsync()
        {
            var businessObject = new List<BoT>();
            var entity = await this.Set().ToListAsync();

            foreach (var entityBase in entity)
            {
                businessObject.Add(this.ConvertToBo(entityBase));
            }

            return businessObject;
        }

        /// <summary>
        /// 根据给定的搜索条件寻找最大值
        /// </summary>
        /// <param name="fliter"></param>
        /// <param name="maxCriteria"></param>
        /// <typeparam name="TValue"></typeparam>
        /// <returns></returns>
        public virtual async Task<TResult> FindMaxAsync<TResult>(Expression<Func<TEntity, bool>> fliter,Expression<Func<TEntity, TResult>> maxCriteria)
        {
            var result = await this.Set().Where(fliter).MaxAsync(maxCriteria);

            return result;
        }

        /// <summary>
        /// 根据keyId寻找业务对象
        /// </summary>
        /// <returns>KeyId所对应的业务对象，或者NULL</returns>
        public virtual async Task<BoT> FindAsync(Guid keyId)
        {
            var entity = await this.Set().FindAsync(keyId);
            return ConvertToBo(entity);
        }

        /// <summary>
        /// 根据keyId寻找业务对象
        /// </summary>
        /// <returns>KeyId所对应的业务对象，或者NULL</returns>
        public virtual async Task<List<BoT>> FindAsync(params Guid[] keyId)
        {
            var entity = await this.Set().Where(entity => keyId.Contains(entity.KeyId)).ToListAsync();
            return ConvertToBo(entity);
        }

        /// <summary>
        /// 根据给定的搜索条件寻找业务对象
        /// </summary>
        /// <param name="fliter">搜索条件</param>
        /// <returns></returns>
        public virtual async Task<IList<BoT>> FindAsync(Expression<Func<TEntity, bool>> fliter)
        {
            var entity = await this.Set().Where(fliter).ToListAsync();
            return ConvertToBo(entity);
        }

        /// <summary>
        /// 根据给定的搜索条件寻找业务对象，返回列表按照给定的方式排序
        /// </summary>
        /// <param name="fliter">搜索条件</param>
        /// <param name="sortCriteria">排序方式</param>
        /// <param name="ascending">倒叙还是正序</param>
        /// <returns></returns>
        public virtual async Task<IList<BoT>> FindBySortAsync<Sort>(Expression<Func<TEntity, bool>> fliter,
            Expression<Func<TEntity, Sort>> sortCriteria, bool ascending = true)
        {
            List<TEntity> entityList;
            if (ascending)
            {
                entityList = await this.Set().Where(fliter).OrderByDescending(sortCriteria).ToListAsync();
            }
            else
            {
                entityList = await this.Set().Where(fliter).OrderBy(sortCriteria).ToListAsync();
            }

            return ConvertToBo(entityList);
        }

        /// <summary>
        /// 根据给定的搜索条件寻找业务对象
        /// </summary>
        /// <param name="fliter">搜索条件</param>
        /// <param name="sortCriteria">排序方式</param>
        /// <param name="pageIndex">页码号，从1开始</param>
        /// <param name="pageSize">每页的对象个数</param>
        /// <param name="ascending">倒叙还是正序</param>
        /// <returns></returns>
        public virtual async Task<(IList<BoT>, int)> FindPagingAsync<Sort>(Expression<Func<TEntity, bool>> fliter,
            Expression<Func<TEntity, Sort>> sortCriteria, int? pageIndex, int? pageSize, bool ascending = true)
        {
            pageIndex = pageIndex.HasValue ? 1 : pageIndex.Value;
            pageSize = pageSize.HasValue ? 10 : pageSize.Value;

            var query = this.Set().Where(fliter);

            query = @ascending ? query.OrderByDescending(sortCriteria) : query.OrderBy(sortCriteria);

            var count = await query.CountAsync();
            var data = await query.Skip(pageIndex.Value).Take(pageSize.Value).ToListAsync();

            return (this.ConvertToBo(data), count);
        }

        #endregion

        #region IRepositoryWriteBase

        /// <summary>
        /// 把一个新建的业务对象交给Repository管理
        /// </summary>
        /// <param name="item">新建的业务对象</param>
        public virtual async Task AddAsync(BoT item)
        {
            await this.Set().AddAsync(this.ConvertToEntity(item));
        }

        /// <summary>
        /// 把指定的业务对象从repository中删除
        /// </summary>
        /// <param name="item">需要被删除的业务对象</param>
        public virtual async Task RemoveAsync(BoT item)
        {
            await Task.Run(() => { this.Set().Remove(this.ConvertToEntity(item)); });
        }

        /// <summary>
        /// 把指定的业务对象从repository中更新
        /// </summary>
        /// <param name="item"></param>
        public virtual async Task UpdateAsync(BoT item)
        {
            await Task.Run(() => { this.Set().Update(this.ConvertToEntity(item)); });
        }

        #endregion

        private TEntity ConvertToEntity(BoT item)
        {
            return (TEntity) item.GetEntity();
        }

        /// <summary>
        /// Entities 转换为领域对象
        /// </summary>
        /// <param name="entity"></param>
        /// <returns></returns>
        private List<BoT> ConvertToBo(List<TEntity> entity)
        {
            var list = new List<BoT>();

            foreach (var boBase in entity)
                list.Add(ConvertToBo(boBase));

            return list;
        }

        /// <summary>
        /// Entities 转换为领域对象
        /// </summary>
        /// <param name="entity"></param>
        /// <returns></returns>
        private BoT ConvertToBo(TEntity entity)
        {
            return (BoT) (Activator.CreateInstance(typeof(BoT), new object[] {entity}));
        }
    }
}